package com.fsh.subject.domain.service.impl;

import com.alibaba.fastjson.JSON;
import com.fsh.subject.common.enums.IsDeletedFlagEnum;
import com.fsh.subject.domain.convert.SubjectCategoryConverter;
import com.fsh.subject.domain.entity.SubjectCategoryBO;
import com.fsh.subject.domain.entity.SubjectLabelBO;
import com.fsh.subject.domain.service.SubjectCategoryDomainService;
import com.fsh.subject.domain.utils.CacheUtil;
import com.fsh.subject.infra.basic.entity.SubjectCategory;
import com.fsh.subject.infra.basic.entity.SubjectLabel;
import com.fsh.subject.infra.basic.entity.SubjectMapping;
import com.fsh.subject.infra.basic.service.SubjectCategoryService;
import com.fsh.subject.infra.basic.service.SubjectLabelService;
import com.fsh.subject.infra.basic.service.SubjectMappingService;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cglib.core.internal.Function;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SubjectCategoryDomainServiceImpl implements SubjectCategoryDomainService {

    @Resource
    private SubjectCategoryService subjectCategoryService;
    @Resource
    private SubjectMappingService subjectMappingService;
    @Resource
    private SubjectLabelService subjectLabelService;

    @Resource(name="labelThreadPool")
    private ThreadPoolExecutor labelThreadPool;

    @Resource
    private CacheUtil cacheUtil;



    @Override
    public void insert(SubjectCategoryBO subjectCategoryBO) {
        //将SubjectCategoryBO 转换成 SubjectCategory
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convertBoToCategory(subjectCategoryBO);
        subjectCategory.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        subjectCategoryService.insert(subjectCategory);
    }

    /**
     * 查询分类
     *
     * @param subjectCategoryBO 学科类别 博
     * @return {@link List}<{@link SubjectCategoryBO}>
     */
    @Override
    public List<SubjectCategoryBO> queryCategory(SubjectCategoryBO subjectCategoryBO) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convertBoToCategory(subjectCategoryBO);
        subjectCategory.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        List<SubjectCategory> subjectCategoryList = subjectCategoryService.queryCategory(subjectCategory);
        List<SubjectCategoryBO> subjectCategoryBOList = SubjectCategoryConverter.INSTANCE.convertCategoryToBo(subjectCategoryList);
        if (log.isInfoEnabled()) {
            log.info("SubjectCategoryController.queryPrimaryCategory.boList:{}",
                    JSON.toJSONString(subjectCategoryBOList));
        }
        //如果查询的是大类，那么就查询每个大类下的题目数量
        if(subjectCategory.getCategoryType()==1){
            subjectCategoryBOList.forEach(bo->{
                Integer count=subjectCategoryService.querySubjectCount(bo.getId());
                bo.setCount(count);
            });
        }
        return subjectCategoryBOList;
    }

    //------------------------------------------------------------
    /**
     * 一次性查询二级分类和它的标签
     */
    @Override
    public List<SubjectCategoryBO> queryCategoryAndLabel(SubjectCategoryBO subjectCategoryBO) {
        String cacheKey="categoryAndLabel."+subjectCategoryBO.getId();
        List<SubjectCategoryBO> bos= cacheUtil.getResult(cacheKey, SubjectCategoryBO.class,
                (key) -> getSubjectCategoryBOS(subjectCategoryBO));
        return bos;
    }

    //提取方法
    private List<SubjectCategoryBO> getSubjectCategoryBOS(SubjectCategoryBO subjectCategoryBO) {
        //先查询这个大类下的所有二级分类
        SubjectCategory subjectCategory=new SubjectCategory();
        subjectCategory.setParentId(subjectCategoryBO.getId());
        subjectCategory.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        List<SubjectCategory> subjectCategoryList = subjectCategoryService.queryCategory(subjectCategory);
        if (log.isInfoEnabled()) {
            log.info("SubjectCategoryController.queryCategoryAndLabel.subjectCategoryList:{}",
                    JSON.toJSONString(subjectCategoryList));
        }
        //转换成bolist
        List<SubjectCategoryBO> categoryBOList = SubjectCategoryConverter.INSTANCE.convertCategoryToBo(subjectCategoryList);
        //一次性获取标签信息。根据分类id。

        //线程池并发调用，使用CompletableFuture
        List<CompletableFuture<Map<Long, List<SubjectLabelBO>>>> completableFutureList = categoryBOList.stream().map(category ->
                CompletableFuture.supplyAsync(() -> getSubjectLabelBOS(category), labelThreadPool)
        ).collect(Collectors.toList());
        //处理完任务后，取出数据
        Map<Long, List<SubjectLabelBO>> resultMap=new HashMap<>();
        completableFutureList.forEach(future->{
            try {
                Map<Long, List<SubjectLabelBO>> map = future.get();
                if(!CollectionUtils.isEmpty(map)){
                    resultMap.putAll(map);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        //从map中拿取数据
        categoryBOList.forEach(bo->{
            bo.setLabelBOList(resultMap.get(bo.getId()));
        });
        return categoryBOList;
    }

    //提取方法， map：key为 二级分类id，value为该分类下的所有标签
    private Map<Long,List<SubjectLabelBO>> getSubjectLabelBOS(SubjectCategoryBO categoryBo) {
        Map<Long,List<SubjectLabelBO>> labelMap=new HashMap<>();

        SubjectMapping subjectMapping=new SubjectMapping();
        subjectMapping.setCategoryId(categoryBo.getId());
        //根据分类id查询所有标签信息
        List<SubjectMapping> subjectMappingList = subjectMappingService.queryLabelId(subjectMapping);
        if(CollectionUtils.isEmpty(subjectMappingList)){
            return null;
        }
        //收集出所有的labelId
        List<Long> labelIdList = subjectMappingList.stream().map(SubjectMapping::getLabelId).collect(Collectors.toList());
        //根据labelId查询出每个标签的详细信息
        List<SubjectLabel> labelList = subjectLabelService.batchQueryById(labelIdList);

        List<SubjectLabelBO> labelBOList=new ArrayList<>();
        labelList.forEach(label->{
            SubjectLabelBO labelBO=new SubjectLabelBO();
            labelBO.setId(label.getId());
            labelBO.setCategoryId(label.getCategoryId());
            labelBO.setLabelName(label.getLabelName());
            labelBO.setSortNum(labelBO.getSortNum());
            labelBOList.add(labelBO);
        });
        labelMap.put(categoryBo.getId(),labelBOList);
        return labelMap;
    }

    //--------------------------------------------------------
    /**
     * 更新分类
     *
     * @param subjectCategoryBO
     * @return {@link Boolean}
     */
    @Override
    public Boolean update(SubjectCategoryBO subjectCategoryBO) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convertBoToCategory(subjectCategoryBO);
        int update = subjectCategoryService.update(subjectCategory);
        return update>0;
    }

    @Override
    public Boolean delete(SubjectCategoryBO subjectCategoryBO) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convertBoToCategory(subjectCategoryBO);
        subjectCategory.setIsDeleted(IsDeletedFlagEnum.DELETED.getCode());
        int updateCount = subjectCategoryService.update(subjectCategory);
        return updateCount>0;
    }


}
